package com.shelpe.services.sinbad.controller;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shelpe.services.sinbad.controller.dto.BaseDTO;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.AdgroupLog;
import com.shelpe.services.sinbad.entity.jpa.Campaign;
import com.shelpe.services.sinbad.entity.jpa.Campaign.Area;
import com.shelpe.services.sinbad.entity.jpa.Campaign.ScheduleObject;
import com.shelpe.services.sinbad.entity.jpa.CampaignHistory;
import com.shelpe.services.sinbad.entity.jpa.CampaignLog;
import com.shelpe.services.sinbad.entity.jpa.DriveType;
import com.shelpe.services.sinbad.entity.jpa.OnlineStatus;
import com.shelpe.services.sinbad.entity.jpa.TransformUsers;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.entity.jpa.vo.AdgroupVo;
import com.shelpe.services.sinbad.entity.jpa.vo.CampaignVo;
import com.shelpe.services.sinbad.entity.jpa.vo.ConvertPlatformVo;
import com.shelpe.services.sinbad.entity.jpa.vo.PlatformVo;
import com.shelpe.services.sinbad.model.Keyword;
import com.shelpe.services.sinbad.model.RptCampaign;
import com.shelpe.services.sinbad.model.RptKeyword;
import com.shelpe.services.sinbad.model.RptKeywordExample;
import com.shelpe.services.sinbad.model.RptKeywordParam;
import com.shelpe.services.sinbad.repository.jpa.AdgroupLogRepository;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignHistoryRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignLogRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignRepository;
import com.shelpe.services.sinbad.repository.jpa.ProductRepository;
import com.shelpe.services.sinbad.repository.jpa.TransformUsersRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.service.PlatformService;
import com.shelpe.services.sinbad.service.RptCampaignService;
import com.shelpe.services.sinbad.service.RptKeywordService;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignAreaDto;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignAreaResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignBudgetDto;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignBudgetResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignOnlineStatusDto;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignPlatformDto;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignPlatformResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignScheduleDto;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CampaignScheduleResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.CreateCampaignResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.UpdateCampaignAreaResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.UpdateCampaignBudgetResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.UpdateCampaignPlatformResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.UpdateCampaignResponse;
import com.shelpe.services.sinbad.service.simbaproxy.CampaignClient.UpdateCampaignScheduleResponse;
import com.shelpe.services.sinbad.service.simbaproxy.SimbaProxyBaseDto;
import com.shelpe.services.sinbad.utils.CampaignUtils;
import com.shelpe.services.sinbad.utils.DateUtil;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/sinbadservice")
@Slf4j
@Api(value = "推广计划相关的API", consumes = "application/json", produces = "application/json")
public class CampaignController {

	@Autowired
	private CampaignLogRepository campaignLogRepository;
	@Autowired
	private AdgroupLogRepository adgroupLogRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private CampaignRepository campaignRepository;
	@Autowired
	private CampaignClient campaignClient;
	@Autowired
	private ObjectMapper objectMapper;

	@Autowired
	private RptKeywordService rptKeywordService;

	@Autowired
	private PlatformService platformService;

	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private CampaignHistoryRepository campaignHistoryRepository;
	@Autowired
	private RptCampaignService rptCampaignService;
	@Autowired
	private ProductRepository productRepository;
	@Autowired
	private TransformUsersRepository transformUsersRepository;

	public final static String WHOLE_DAY = "00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100";

	@ApiOperation(value = "创建推广计划")
	@ApiResponses({ @ApiResponse(code = 500, message = "user_not_foud"),
			@ApiResponse(code = 500, message = "exceed_limit_20") })
	@RequestMapping(method = RequestMethod.POST, path = "/campaigns")
	@ResponseBody
	public CampaignDto createCampaign(@RequestBody CampaignDto dto) {
		log.info("begin createCampaign: {}", dto);
		User user = this.userRepository.findOne(dto.getUserID());
		Assert.notNull(user, "user_not_foud");

		int existingCount = this.campaignRepository.countByUserID(user.getUserID());
		Assert.isTrue(existingCount < 20, "exceed_limit_20");
		List<Campaign> campaigns = this.campaignRepository.findByUserID(user.getUserID());
		if (campaigns != null && campaigns.size() > 0) {
			for (Campaign campaignCheck : campaigns) {
				if (dto.getTitle().equals(campaignCheck.getTitle())) {
					Assert.isTrue(false, "this title is repeat");
				}
			}
		}

		log.info("开始创建推广计划: {},{},{}", user, dto, existingCount);
		CreateCampaignResponse res = this.campaignClient.createCampaign(user.getNick(), dto.getTitle());
		log.info("************:{},{},{}", res, user.getNick(), dto.getTitle());
		if (res != null && res.getRes() != null && res.getRes().getCampaign() != null) {
			CampaignClient.CampaignDto tbDto = res.getRes().getCampaign();
			log.info("sync to taobao: {}", tbDto);

			Campaign campaign = new Campaign();
			BeanUtils.copyProperties(tbDto, campaign);
			campaign.setAutoID(tbDto.getCampaignID());
			campaign.setAutoType(DriveType.manual);
			campaign.setSettleStatus(OnlineStatus.from(tbDto.getSettleStatus()));
			campaign.setOnlineStatus(OnlineStatus.from(tbDto.getOnlineStatus()));
			campaign.setIncrementalPrice("");
			campaign.setPlatform("投放平台设置JSON字符串");
			campaign.setUseSmooth(true);
			campaign.setUserID(dto.getUserID());
			campaign.setUpdatedTime(new Date());
			campaign.setTitle(dto.getTitle());

			log.info("****推广计划一号****: {}", campaign);
			this.campaignRepository.save(campaign);

			if (dto.getBudget() >= 30) {
				UpdateCampaignBudgetResponse ucbRes = this.campaignClient.updateCampaignBudget(user.getNick(),
						campaign.getAutoID(), dto.getBudget(), true);
				if (ucbRes != null && ucbRes.getRes() != null && ucbRes.getRes().getBudget() != null) {
					CampaignBudgetDto tbBudgetDto = ucbRes.getRes().getBudget();
					campaign.setBudget(tbBudgetDto.getBudget());
					campaign.setUseSmooth(tbBudgetDto.isUseSmooth());
					campaign.setUpdatedTime(new Date());
					log.info("****推广计划updateCampaignBudget****: {}", campaign);
					this.campaignRepository.save(campaign);
				}
				if (ucbRes != null && ucbRes.getError() != null && ucbRes.getError().getSubMessage() != null) {
					log.error("updateCampaignBudget : {}", ucbRes.getError().getSubMessage());
				}
			} else {
				CampaignBudgetResponse cbRes = this.campaignClient.findCampaignBudget(user.getNick(),
						campaign.getAutoID());
				if (cbRes != null && cbRes.getRes() != null && cbRes.getRes().getBudget() != null) {
					CampaignBudgetDto tbBudgetDto = cbRes.getRes().getBudget();
					campaign.setBudget(tbBudgetDto.getBudget());
					campaign.setUseSmooth(tbBudgetDto.isUseSmooth());
					campaign.setUpdatedTime(new Date());
					log.info("****推广计划findCampaignBudget****: {}", campaign);
					this.campaignRepository.save(campaign);
				}
				if (cbRes != null && cbRes.getError() != null && cbRes.getError().getSubMessage() != null) {
					log.error("findCampaignBudget : {}", cbRes.getError().getSubMessage());
				}

			}

			if (dto.getArea() != null) {
				log.debug("sync campaign area: {}", campaign);
				String areaString = CampaignUtils.fromArea(dto.getArea());
				UpdateCampaignAreaResponse ucaRes = this.campaignClient.updateCampaignArea(user.getNick(),
						campaign.getAutoID(), areaString);
				if (ucaRes != null && ucaRes.getRes() != null && ucaRes.getRes().getArea() != null) {
					CampaignAreaDto tbAreaDto = ucaRes.getRes().getArea();
					campaign.setArea(CampaignUtils.toArea(tbAreaDto.getArea()));
					campaign.setUpdatedTime(new Date());
					log.info("****推广计划updateCampaignArea****: {}", campaign);
					this.campaignRepository.save(campaign);
				}
				if (ucaRes != null && ucaRes.getError() != null && ucaRes.getError().getSubMessage() != null) {
					log.error("updateCampaignArea : {}", ucaRes.getError().getSubMessage());
				}
			} else {
				CampaignAreaResponse caRes = this.campaignClient.findCampaignArea(user.getNick(), campaign.getAutoID());
				if (caRes != null && caRes.getRes() != null && caRes.getRes().getArea() != null) {
					CampaignAreaDto tbAreaDto = caRes.getRes().getArea();
					campaign.setArea(CampaignUtils.toArea(tbAreaDto.getArea()));
					campaign.setUpdatedTime(new Date());
					log.info("****推广计划findCampaignArea****: {}", campaign);
					this.campaignRepository.save(campaign);
				}
				if (caRes != null && caRes.getError() != null && caRes.getError().getSubMessage() != null) {
					log.error("findCampaignArea : {}", caRes.getError().getSubMessage());
				}
			}

			if (dto.getScheduleObject() != null) {
				String schedule = CampaignUtils.fromScheduleObject(dto.getScheduleObject());
				dto.setSchedule(schedule);
			}
			if (dto.getSchedule() != null && dto.getSchedule().equals(
					"00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100")) {
				dto.setSchedule("all");
			}
			if (dto.getSchedule() != null) {
				log.debug("sync campaign schedule: {} ||{}", campaign, dto);
				UpdateCampaignScheduleResponse ucsRes = this.campaignClient.updateCampaignSchedule(user.getNick(),
						campaign.getAutoID(), dto.getSchedule());
				if (ucsRes != null && ucsRes.getRes() != null && ucsRes.getRes().getSchedule() != null) {
					CampaignScheduleDto tbScheduleDto = ucsRes.getRes().getSchedule();
					campaign.setUpdatedTime(new Date());
					campaign.setSchedule(tbScheduleDto.getSchedule());
					this.campaignRepository.save(campaign);
					log.debug("********campaign resSchedule********: {}", campaign);
				}
				if (ucsRes != null && ucsRes.getError() != null) {
					log.error("updateCampaignSchedule:{}", ucsRes.getError().getMessage());
				}
			} else {
				CampaignScheduleResponse csRes = this.campaignClient.findCampaignSchedule(user.getNick(),
						campaign.getAutoID());
				if (csRes != null && csRes.getRes() != null && csRes.getRes().getSchedule() != null) {
					CampaignScheduleDto tbScheduleDto = csRes.getRes().getSchedule();
					campaign.setSchedule(tbScheduleDto.getSchedule());
					campaign.setSchedule(tbScheduleDto.getSchedule());
					campaign.setUpdatedTime(new Date());
					log.info("****推广计划findCampaignSchedule****: {}", campaign);
					this.campaignRepository.save(campaign);
				}
				if (csRes != null && csRes.getError() != null && csRes.getError().getSubMessage() != null) {
					log.error("findCampaignSchedule : {}", csRes.getError().getSubMessage());
				}
			}

			if (dto.getPlatform() != null) {
				PlatformVo vo = new PlatformVo();
				BeanUtils.copyProperties(campaign, vo);
				vo.setCampaignID(campaign.getAutoID());
				vo.setNick(campaign.getNick());
				this.toPlatformDto(dto, vo);
				try {
					dto.setPlatfromTemp(this.objectMapper.writer().writeValueAsString(vo)); // 将页面的平台设置值转化为跟数据库匹配
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
				}
			}

			if (dto.getPlatfromTemp() != null) {
				log.debug("sync campaign platform: {}", dto); // 到时改debug日志
				PlatformVo vo = new PlatformVo();
				BeanUtils.copyProperties(campaign, vo);
				vo.setCampaignID(campaign.getAutoID());
				vo.setNick(campaign.getNick());
				this.toPlatformDto(dto, vo);
				UpdateCampaignPlatformResponse ucpfRes = this.campaignClient.updateCampaignPlatform(user.getNick(),
						campaign.getAutoID(), dto.getPlatform().toSearchChannels(),
						dto.getPlatform().toNonsearchChannels(), vo.getOutsideDiscount(), vo.getMobileDiscount());
				if (ucpfRes != null && ucpfRes.getRes() != null && ucpfRes.getRes().getPlatform() != null) {
					CampaignPlatformDto tbPlatformDto = ucpfRes.getRes().getPlatform();
					BeanUtils.copyProperties(vo, tbPlatformDto);
					tbPlatformDto.setCampaignID(campaign.getAutoID());
					tbPlatformDto.setMobileDiscount(vo.getMobileDiscount());
					tbPlatformDto.setNick(vo.getNick());
					tbPlatformDto.setNonsearchChannels(vo.getNonsearchChannels());
					tbPlatformDto.setOutsideDiscount(vo.getOutsideDiscount());
					tbPlatformDto.setSearchChannels(vo.getSearchChannels());

					campaign.setPlatform(platformService.serialize(vo));
					campaign.setUpdatedTime(new Date());
					this.campaignRepository.save(campaign);
					log.debug("********campaign resPlatform********: {}||{}", campaign, ucpfRes);
				}
				if (ucpfRes != null && ucpfRes.getError() != null) {
					log.error("updateCampaignPlatform : {}", ucpfRes.getError().getMessage());
				}
			} else {
				dto.setCampaignID(campaign.getAutoID());
				log.debug("sync campaign platform: {}", dto);
				PlatformVo vo = new PlatformVo();
				CampaignPlatformResponse cpfRes = this.campaignClient.findCampaignPlatform(user.getNick(),
						campaign.getAutoID());
				if (cpfRes != null && cpfRes.getRes() != null && cpfRes.getRes().getPlatform() != null) {
					CampaignPlatformDto campaignPlatformDto = cpfRes.getRes().getPlatform();
					vo.setCreateTime(campaign.getCreateTime());
					vo.setModifiedTime(campaign.getModifiedTime());
					vo.setNick(campaign.getNick());
					vo.setCampaignID(campaignPlatformDto.getCampaignID());
					vo.setMobileDiscount(campaignPlatformDto.getMobileDiscount());
					vo.setNonsearchChannels(campaignPlatformDto.getNonsearchChannels());
					vo.setSearchChannels(campaignPlatformDto.getSearchChannels());
					vo.setOutsideDiscount(campaignPlatformDto.getOutsideDiscount());

					campaign.setPlatform(platformService.serialize(vo));
					campaign.setUpdatedTime(new Date());
					log.info("****推广计划findCampaignPlatform****: {}", campaign);
					this.campaignRepository.save(campaign);
				}
				if (cpfRes != null && cpfRes.getError() != null && cpfRes.getError().getSubMessage() != null) {
					log.error("findCampaignPlatform : {}", cpfRes.getError().getSubMessage());
				}

			}
			dto.setCampaignID(campaign.getAutoID());

			CampaignLog po = new CampaignLog();
			BeanUtils.copyProperties(campaign, po);
			po.setAction(CampaignLog.Action.ADD);
			po.setCampaignID(campaign.getAutoID());
			po.setUpdatedTime(new Date());
			try {
				po.setNote(this.objectMapper.writer().writeValueAsString(campaign));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
				po.setNote("");
			}

			this.campaignLogRepository.save(po);
			log.debug("sync campaign CampaignLog: {}", po);

		} else {
			log.error("fail createCampaign: {}", res.getError().getSubMessage());
		}

		log.debug("finish createCampaign: {}", dto);
		return dto;
	}

	@ApiOperation(value = "修改推广计划")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "action_types", defaultValue = "manual", allowableValues = "auto,manual", paramType = "query", dataType = "string", allowMultiple = true) })
	@RequestMapping(method = RequestMethod.PUT, path = "/campaigns/{campaign_id}")
	@ResponseBody
	public CampaignDto updateCampaign(
			@RequestParam(name = "action_types", defaultValue = "manual") List<String> actionTypes,
			@PathVariable("campaign_id") long campaignID, @RequestBody CampaignDto dto) {
		boolean isManual = false;
		boolean isAuto = false;
		if (actionTypes != null) {
			isManual = actionTypes.indexOf("manual") > -1;
			isAuto = actionTypes.indexOf("auto") > -1;
		}

		Campaign campaign = this.campaignRepository.findOne(campaignID);
		Assert.notNull(campaign, "campaign_not_found");
		List<Campaign> campaigns = this.campaignRepository.findByUserID(campaign.getUserID());
		log.debug("begin updateCampaign: {} {}", campaignID, dto);
		User user = this.userRepository.findOne(campaign.getUserID());
		if (user == null) {
			throw new IllegalArgumentException("user_not_foud");
		}
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (dto.getBudget() >= 30 && dto.getBudget() != campaign.getBudget()) {
			CampaignVo cvo = new CampaignVo();
			cvo.setNewBudget(dto.getBudget());
			cvo.setOldBudget(campaign.getBudget());
			cvo.setCreateTime(campaign.getCreateTime());
			cvo.setModifiedTime(campaign.getModifiedTime());
			cvo.setAutoID(campaign.getAutoID());
			log.debug("sync campaign budget: {}", campaign);

			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "budget");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(new Date());
				campaignHistory.setActionType("budget");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("finish budget:{}", campaignHistory);
			}

			UpdateCampaignBudgetResponse ucbRes = this.campaignClient.updateCampaignBudget(user.getNick(),
					campaign.getAutoID(), dto.getBudget(), true);
			if (ucbRes != null && ucbRes.getRes() != null && ucbRes.getRes().getBudget() != null) {
				log.debug("updateCampaignBudget res: {}", ucbRes.getRes().getBudget());
				CampaignBudgetDto tbBudgetDto = ucbRes.getRes().getBudget();
				campaign.setBudget(tbBudgetDto.getBudget());
				campaign.setUseSmooth(tbBudgetDto.isUseSmooth());
				campaign.setUpdatedTime(new Date());
				this.campaignRepository.save(campaign);
				log.debug("campaign res: {}", campaign);
				dto.setSuccess(true);

				CampaignLog po = new CampaignLog();
				BeanUtils.copyProperties(campaign, po);
				po.setCampaignID(campaign.getAutoID());
				po.setAction(CampaignLog.Action.UPDATE_BUDGET);
				po.setNewIntval(campaign.getBudget());
				po.setCampaignID(campaign.getAutoID());
				po.setUpdatedTime(new Date());
				try {
					po.setNote(this.objectMapper.writer().writeValueAsString(cvo));
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
					po.setNote("");
				}

				this.campaignLogRepository.save(po);
				log.debug("sync campaign CampaignLog: {}", po);
			}

			if (ucbRes != null && ucbRes.getError() != null) {
				dto.setError(ucbRes.getError());
				dto.form(ucbRes.getError());
				log.error("updateCampaignBudget:{}", ucbRes.getError());
			}
		}

		Integer[] arr = new Integer[] { 1, 39, 255, 279, 368, 417, 508, 19, 125, 333, 393, 461, 52, 351, 357, 406, 471,
				68, 92, 120, 145, 184, 212, 109, 438, 463, 488, 532, 165, 234, 294, 574, 576, 577, 599 };
		if (dto.getArea() != null && dto.getArea().isAsAll()) {
			dto.getArea().setNums(Arrays.asList(arr));
		}
		if (campaign != null && campaign.getArea() != null && campaign.getArea().isAsAll()) {
			campaign.getArea().setNums(Arrays.asList(arr));
		}

		if (dto.getArea() != null && campaign.getArea() != null && dto.getArea().getNums() != null
				&& campaign.getArea().getNums() != null
				&& !(dto.getArea().getNums().size() == campaign.getArea().getNums().size()
						&& dto.getArea().getNums().containsAll(campaign.getArea().getNums()))) {
			log.info("start update area:{}---{}", campaign.getAutoID(), dto.getArea());
			CampaignVo campaignVo = new CampaignVo();
			if (dto.getArea().isAsAll() == true) {
				dto.getArea().setAsAll(false);
				if (dto.getArea() != null && dto.getArea().getNums().size() > 0 && campaign.getArea() != null
						&& campaign.getArea().getNums() != null) {
					this.toAreaDto(dto.getArea().getNums(), campaign.getArea().getNums(), campaignVo);
				}
			} else if (campaign.getArea().isAsAll() == true) {
				List<Integer> campaignList = new ArrayList<Integer>();
				campaignList = Arrays.asList(arr);
				campaign.getArea().setNums(campaignList);
				campaign.getArea().setAsAll(false);
				if (dto.getArea() != null && dto.getArea().getNums().size() > 0 && campaign.getArea() != null
						&& campaign.getArea().getNums().size() > 0) {
					this.toAreaDto(dto.getArea().getNums(), campaign.getArea().getNums(), campaignVo);
				}
			} else {
				if (dto.getArea() != null && dto.getArea().getNums() != null && dto.getArea().getNums().size() > 0
						&& campaign.getArea() != null && campaign.getArea().getNums() != null
						&& campaign.getArea().getNums().size() > 0) {
					this.toAreaDto(dto.getArea().getNums(), campaign.getArea().getNums(), campaignVo);
				}
			}

			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "area");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
				log.debug("update create finish area:{}", campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(new Date());
				campaignHistory.setActionType("area");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("create finish area:{}", campaignHistory);
			}

			log.debug("sync campaign area: {}||{}", campaign, dto);
			String areaString = CampaignUtils.fromArea(dto.getArea());
			UpdateCampaignAreaResponse ucaRes = this.campaignClient.updateCampaignArea(user.getNick(),
					campaign.getAutoID(), areaString);
			if (ucaRes != null && ucaRes.getRes() != null && ucaRes.getRes().getArea() != null) {
				CampaignAreaDto tbAreaDto = ucaRes.getRes().getArea();
				campaign.setArea(CampaignUtils.toArea(tbAreaDto.getArea()));
				campaign.setUpdatedTime(new Date());
				this.campaignRepository.save(campaign);
				dto.setSuccess(true);
				log.debug("********campaign resArea********: {}", campaign);
				CampaignLog po = new CampaignLog();
				BeanUtils.copyProperties(campaign, po);
				if (isAuto) {
					po.setAction(CampaignLog.Action.AUTO_UPDATE_AREA);
				}
				if (isManual) {
					po.setAction(CampaignLog.Action.UPDATE_AREA);
				}
				po.setCampaignID(campaign.getAutoID());
				po.setUpdatedTime(new Date());
				try {
					po.setNote(this.objectMapper.writer().writeValueAsString(campaignVo));
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
					po.setNote("");
				}

				this.campaignLogRepository.save(po);
				log.debug("sync campaign CampaignLog: {}", po);
			}

			if (ucaRes != null && ucaRes.getError() != null) {
				dto.setError(ucaRes.getError());
				dto.form(ucaRes.getError());
			}

		}

		if (dto.getScheduleObject() != null) {
			if (dto.getScheduleObject().isAsAll()) {
				dto.setSchedule("all");
			} else if (dto.getScheduleObject().getRanges() != null && dto.getScheduleObject().getRanges().size() > 0) {
				String schedule = CampaignUtils.fromScheduleObject(dto.getScheduleObject());
				dto.setSchedule(schedule);
			}
		}
		if (dto.getSchedule() != null && dto.getSchedule().equals(
				"00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100")) {
			dto.setSchedule("all");
		}
		if (dto.getSchedule() != null && !(dto.getSchedule().equals(campaign.getSchedule()))) {
			CampaignVo campaignVo = new CampaignVo();
			if (dto.getSchedule().equals("all")) {
				dto.setSchedule(
						"00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100;00:00-24:00:100");
				campaignVo.setSchedule(CampaignUtils.toScheduleObject(dto.getSchedule()));
			} else {
				campaignVo.setSchedule(CampaignUtils.toScheduleObject(dto.getSchedule()));
			}

			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "schedule");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
				log.debug("update finish schedule:{}", campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(new Date());
				campaignHistory.setActionType("schedule");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("create finish schedule:{}", campaignHistory);
			}

			log.debug("sync campaign schedule: {} ||{}", campaign, dto);
			UpdateCampaignScheduleResponse ucsRes = this.campaignClient.updateCampaignSchedule(user.getNick(),
					campaign.getAutoID(), dto.getSchedule());
			if (ucsRes != null && ucsRes.getRes() != null && ucsRes.getRes().getSchedule() != null) {
				CampaignScheduleDto tbScheduleDto = ucsRes.getRes().getSchedule();
				campaign.setUpdatedTime(new Date());
				campaign.setSchedule(tbScheduleDto.getSchedule());
				this.campaignRepository.save(campaign);
				dto.setSuccess(true);
				log.debug("********campaign resSchedule********: {}", campaign);

				CampaignLog po = new CampaignLog();
				BeanUtils.copyProperties(campaign, po);
				if (isAuto) {
					po.setAction(CampaignLog.Action.AUTO_UPDATE_SCHEDULE);
				}
				if (isManual) {
					po.setAction(CampaignLog.Action.UPDATE_SCHEDULE);
				}
				po.setCampaignID(campaign.getAutoID());
				po.setUpdatedTime(new Date());
				try {
					po.setNote(this.objectMapper.writer().writeValueAsString(campaignVo));
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
					po.setNote("");
				}

				this.campaignLogRepository.save(po);
				log.debug("sync campaign CampaignLog: {}", po);
			}

			if (ucsRes != null && ucsRes.getError() != null) {
				dto.setError(ucsRes.getError());
				dto.form(ucsRes.getError());
				log.error("updateCampaignSchedule:{}", ucsRes.getError());
			}
		} else {
			dto.setSuccess(true);
		}

		if (dto.getTitle() != null && !(dto.getTitle().equals(campaign.getTitle()))
				&& !(campaigns.contains(dto.getTitle()))) {
			TransformUsers tranUser = this.transformUsersRepository.findByUserID(campaign.getUserID());
			if(user.getUserType() == 2 || tranUser != null){
				//同时过滤掉代理用户加后缀名的错误
				if(dto.getTitle().contains("-云智投")){
					dto.setTitle(dto.getTitle().substring(0,dto.getTitle().indexOf("云智投") - 1));
				}
				if(dto.getTitle().contains("云智投")){
					dto.setTitle(dto.getTitle().substring(0,dto.getTitle().indexOf("云智投")));
				}
			}
			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "title");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
				log.debug("update finish title:{}", campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(new Date());
				campaignHistory.setActionType("title");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("create finish title:{}", campaignHistory);
			}

			UpdateCampaignResponse res = this.campaignClient.updateCampaignOnlineStatusWithTitle(user.getNick(),
					dto.getTitle(), campaign.getAutoID(), campaign.getOnlineStatus().getValue());
			log.info("start update campaign title:{}", res);
			if (res != null && res.getRes() != null && res.getRes().getCampaign() != null
					&& res.getRes().getCampaign().getTitle() != null) {
				CampaignVo campaignVo = new CampaignVo();
				campaignVo.setOldTitle(campaign.getTitle());
				campaignVo.setNewTitle(dto.getTitle());
				campaignVo.setCreateTime(campaign.getCreateTime());
				campaignVo.setModifiedTime(campaign.getModifiedTime());

				CampaignOnlineStatusDto tbOnlineStatusDto = res.getRes().getCampaign();
				log.info("start sync campaign taobao title:{}", tbOnlineStatusDto);
				campaign.setTitle(tbOnlineStatusDto.getTitle());
				campaign.setUpdatedTime(new Date());
				this.campaignRepository.save(campaign);
				dto.setSuccess(true);
				log.debug("********finish campaign resTitle********: {}", campaign);

				CampaignLog po = new CampaignLog();
				BeanUtils.copyProperties(campaign, po);
				if (isAuto) {
					po.setAction(CampaignLog.Action.AUTO_UPDATE_TITLE);
				}
				if (isManual) {
					po.setAction(CampaignLog.Action.UPDATE_TITLE);
				}
				po.setCampaignID(campaign.getAutoID());
				po.setUpdatedTime(new Date());
				try {
					po.setNote(this.objectMapper.writer().writeValueAsString(campaignVo));
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
					po.setNote("");
				}
				this.campaignLogRepository.save(po);
				log.debug("sync campaign CampaignLog: {}", po);
			}

			if (res != null && res.getError() != null) {
				dto.setError(res.getError());
				dto.form(res.getError());
				log.error("updateCampaignOnlineStatus:{}", res.getError());
			}

		}

		if (dto.getOnlineStatus() != null && !(dto.getOnlineStatus().equals(campaign.getOnlineStatus()))) {
			CampaignLog po = new CampaignLog();
			BeanUtils.copyProperties(campaign, po);
			if (campaign.getOnlineStatus().getValue().equals("online")) {
				po.setAction(CampaignLog.Action.UPDATE_ONLINE_PAUSE);
			} else {
				po.setAction(CampaignLog.Action.UPDATE_ONLINE_OPEN);
			}

			synchronized (this) {
				Date date = null;
				try {
					date = sdf.parse(sdf.format(new Date()));
				} catch (ParseException e1) {
					log.error("ParseException:{}", e1);
				}
				CampaignHistory campaignHis = this.campaignHistoryRepository
						.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "online_status");
				if (campaignHis != null) {
					campaignHis.setCreateTime(date);
					this.campaignHistoryRepository.save(campaignHis);
					log.debug("update finish online_status:{}", campaignHis);
				} else {
					CampaignHistory campaignHistory = new CampaignHistory();
					BeanUtils.copyProperties(campaign, campaignHistory);
					campaignHistory.setCreateTime(new Date());
					campaignHistory.setActionType("online_status");
					this.campaignHistoryRepository.save(campaignHistory);
					log.debug("create finish online_status:{}", campaignHistory);
				}
			}

			UpdateCampaignResponse res = this.campaignClient.updateCampaignOnlineStatusWithTitle(user.getNick(),
					campaign.getTitle(), campaign.getAutoID(), dto.getOnlineStatus().getValue());
			log.info("start update campaign online_status:{}", res);
			if (res != null && res.getRes() != null && res.getRes().getCampaign() != null
					&& res.getRes().getCampaign().getOnlineStatus() != null) {
				CampaignOnlineStatusDto tbOnlineStatusDto = res.getRes().getCampaign();
				log.info("sync update campaign taobao online_status:{}", tbOnlineStatusDto);
				campaign.setOnlineStatus(OnlineStatus.from(tbOnlineStatusDto.getOnlineStatus()));
				campaign.setUpdatedTime(new Date());
				this.campaignRepository.save(campaign);
				dto.setSuccess(true);
				log.debug("********campaign resOnlineStatus********: {}", campaign);

				po.setCampaignID(campaign.getAutoID());
				po.setUpdatedTime(new Date());
				po.setNote("");

				this.campaignLogRepository.save(po);
				log.debug("sync campaign CampaignLog: {}", po);
			}
			if (res != null && res.getError() != null) {
				dto.setError(res.getError());
				dto.form(res.getError());
				log.error("updateCampaignOnlineStatus:{}", res.getError());
			}

		}

		if (dto.getPlatform() != null) {
			PlatformVo vo = new PlatformVo();
			BeanUtils.copyProperties(campaign, vo);
			vo.setCampaignID(campaign.getAutoID());
			vo.setNick(campaign.getNick());
			this.toPlatformDto(dto, vo);
			try {
				dto.setPlatfromTemp(this.objectMapper.writer().writeValueAsString(vo)); // 将页面的平台设置值转化为跟数据库匹配
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
			}
		}

		if (dto.getPlatfromTemp() != null && !(dto.getPlatfromTemp().equals(campaign.getPlatform()))) {
			CampaignVo campaignVo = new CampaignVo();
			// 将数据库内平台转化,并得出增加的,减少的集合
			PlatformVo convertVo = platformService.unserialize(campaign.getPlatform());
			if (convertVo.getSearchChannels().getNumber() == null) { // 针对为null的时候
				convertVo.getSearchChannels().setNumber(new ArrayList<Integer>());
			}
			if (convertVo.getNonsearchChannels().getNumber() == null) { // 针对为null的时候
				convertVo.getNonsearchChannels().setNumber(new ArrayList<Integer>());
			}
			List<Integer> addPlatformSearch = new ArrayList<Integer>(dto.getPlatform().toSearchChannels());
			List<Integer> lessPlatformSearch = new ArrayList<Integer>(convertVo.getSearchChannels().getNumber());
			List<Integer> addPlatformNon = new ArrayList<Integer>(dto.getPlatform().toNonsearchChannels());
			List<Integer> lessPlatformNon = new ArrayList<Integer>(convertVo.getNonsearchChannels().getNumber());
			addPlatformSearch.removeAll(convertVo.getSearchChannels().getNumber());
			lessPlatformSearch.removeAll(dto.getPlatform().toSearchChannels());
			addPlatformNon.removeAll(convertVo.getNonsearchChannels().getNumber());
			lessPlatformNon.removeAll(dto.getPlatform().toNonsearchChannels());

			// 将得到的减少,增加的集合进行转化为boolean值类型
			PlatformVo addVo = new PlatformVo();
			addVo.setNonsearchChannels(new PlatformVo.Channels());
			addVo.getNonsearchChannels().setNumber(addPlatformNon);
			addVo.setSearchChannels(new PlatformVo.Channels());
			addVo.getSearchChannels().setNumber(addPlatformSearch);
			dto.setConvertPlatformVo(new ConvertPlatformVo());
			dto.getConvertPlatformVo().fromSearch(addVo);
			dto.getConvertPlatformVo().fromNonSearch(addVo);
			dto.getConvertPlatformVo().setMobileDiscount(convertVo.getMobileDiscount());
			dto.getConvertPlatformVo().setOutsideDiscount(convertVo.getOutsideDiscount());
			campaignVo.setAddPlatform(dto.getConvertPlatformVo());

			PlatformVo lessVo = new PlatformVo();
			lessVo.setNonsearchChannels(new PlatformVo.Channels());
			lessVo.getNonsearchChannels().setNumber(lessPlatformNon);
			lessVo.setSearchChannels(new PlatformVo.Channels());
			lessVo.getSearchChannels().setNumber(lessPlatformSearch);
			dto.setConvertPlatformVo(new ConvertPlatformVo());
			dto.getConvertPlatformVo().fromSearch(lessVo);
			dto.getConvertPlatformVo().fromNonSearch(lessVo);
			dto.getConvertPlatformVo().setMobileDiscount(dto.getPlatform().getMobileDiscount());
			dto.getConvertPlatformVo().setOutsideDiscount(dto.getPlatform().getOutsideDiscount());
			campaignVo.setLessPlatform(dto.getConvertPlatformVo());

			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "platfrom");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
				log.debug("update finish platfrom:{}", campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(new Date());
				campaignHistory.setActionType("platfrom");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("create finish platfrom:{}", campaignHistory);
			}

			log.debug("sync campaign platform: {}", dto); // 到时改debug日志
			PlatformVo vo = new PlatformVo();
			BeanUtils.copyProperties(campaign, vo);
			vo.setCampaignID(campaign.getAutoID());
			vo.setNick(campaign.getNick());
			this.toPlatformDto(dto, vo);
			UpdateCampaignPlatformResponse ucpfRes = this.campaignClient.updateCampaignPlatform(user.getNick(),
					campaign.getAutoID(), dto.getPlatform().toSearchChannels(), dto.getPlatform().toNonsearchChannels(),
					vo.getOutsideDiscount(), vo.getMobileDiscount());
			if (ucpfRes != null && ucpfRes.getRes() != null && ucpfRes.getRes().getPlatform() != null) {
				CampaignPlatformDto tbPlatformDto = ucpfRes.getRes().getPlatform();
				BeanUtils.copyProperties(vo, tbPlatformDto);
				tbPlatformDto.setCampaignID(campaign.getAutoID());
				tbPlatformDto.setNick(vo.getNick());
				tbPlatformDto.setNonsearchChannels(vo.getNonsearchChannels());
				tbPlatformDto.setSearchChannels(vo.getSearchChannels());
				tbPlatformDto.setOutsideDiscount(vo.getOutsideDiscount());
				tbPlatformDto.setMobileDiscount(vo.getMobileDiscount());
				// 更新平台移动溢价,需同步宝贝移动溢价
				platformService.updateAdgroupMobileDiscount(campaignID, convertVo.getMobileDiscount(),
						vo.getMobileDiscount());
				campaign.setPlatform(platformService.serialize(vo));
				campaign.setUpdatedTime(new Date());
				this.campaignRepository.save(campaign);
				dto.setSuccess(true);
				log.debug("********campaign resPlatform********: {}||{}", campaign, ucpfRes);

				CampaignLog po = new CampaignLog();
				BeanUtils.copyProperties(campaign, po);
				if (isAuto) {
					po.setAction(CampaignLog.Action.AUTO_UPDATE_PLATFORM);
				}
				if (isManual) {
					po.setAction(CampaignLog.Action.UPDATE_PLATFORM);
				}
				po.setCampaignID(campaign.getAutoID());
				po.setUpdatedTime(new Date());
				try {
					po.setNote(this.objectMapper.writer().writeValueAsString(campaignVo));
				} catch (JsonProcessingException e) {
					log.error("JsonProcessingException: {}", e);
				}
				this.campaignLogRepository.save(po);
				log.debug("sync campaign CampaignLog: {}", po);
			}
			if (ucpfRes != null && ucpfRes.getError() != null) {
				dto.setError(ucpfRes.getError());
				dto.form(ucpfRes.getError());
				log.error("updateCampaignPlatform : {}", ucpfRes.getError());
			}
		}

		if (dto.getCampaignLimit() > 0 && (dto.getCampaignLimit() != campaign.getCampaignLimit())) {
			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "auto_type");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
				log.debug("update finish auto_type:{}", campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(date);
				campaignHistory.setActionType("auto_type");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("create finish auto_type:{}", campaignHistory);
			}

			CampaignVo campaignVo = new CampaignVo();
			campaignVo.setOldLimit(campaign.getLimit());
			campaignVo.setNewLimit(dto.getCampaignLimit());

			campaign.setCampaignLimit(dto.getCampaignLimit());
			campaign.setUpdatedTime(new Date());
			this.campaignRepository.save(campaign);
			dto.setSuccess(true);
			log.debug("finish update limit:{}", campaign);

			CampaignLog po = new CampaignLog();
			BeanUtils.copyProperties(campaign, po);
			if (isAuto) {
				po.setAction(CampaignLog.Action.AUTO_UPDATE_CAMPAIGN_LIMIT);
			}
			if (isManual) {
				po.setAction(CampaignLog.Action.UPDATE_CAMPAIGN_LIMIT);
			}
			po.setCampaignID(campaign.getAutoID());
			po.setUpdatedTime(new Date());
			try {
				po.setNote(this.objectMapper.writer().writeValueAsString(campaignVo));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
				po.setNote("");
			}
			// this.campaignLogRepository.save(po);
			log.debug("sync campaign CampaignLog: {}", po);

		}

		if (dto.getAutoType() != null && !(dto.getAutoType().equals(campaign.getAutoType()))
				&& dto.getAutoType().getValue() >= 0) {
			Date date = null;
			try {
				date = sdf.parse(sdf.format(new Date()));
			} catch (ParseException e1) {
				log.error("ParseException:{}", e1);
			}
			CampaignHistory campaignHis = this.campaignHistoryRepository
					.findByAutoIDAndCreateTimeAndActionType(campaign.getAutoID(), date, "auto_type");
			if (campaignHis != null) {
				campaignHis.setCreateTime(date);
				this.campaignHistoryRepository.save(campaignHis);
				log.debug("update finish auto_type:{}", campaignHis);
			} else {
				CampaignHistory campaignHistory = new CampaignHistory();
				BeanUtils.copyProperties(campaign, campaignHistory);
				campaignHistory.setCreateTime(date);
				campaignHistory.setActionType("auto_type");
				this.campaignHistoryRepository.save(campaignHistory);
				log.debug("create finish auto_type:{}", campaignHistory);
			}

			CampaignVo campaignVo = new CampaignVo();
			campaignVo.setOldAutoType(campaign.getAutoType());

			campaign.setPreviousAutoType(campaign.getAutoType());
			campaign.setAutoType(dto.getAutoType());
			campaign.setUpdatedTime(new Date());
			campaign.setChangeTime(new Date());
			this.campaignRepository.save(campaign);
			dto.setSuccess(true);
			log.debug("finish update auto_type:{}", campaign);
			campaignVo.setNewAutoType(campaign.getAutoType());

			CampaignLog po = new CampaignLog();
			BeanUtils.copyProperties(campaign, po);
			if (isAuto) {
				po.setAction(CampaignLog.Action.AUTO_UPDATE_AUTO_TYPE);
			}
			if (isManual) {
				po.setAction(CampaignLog.Action.UPDATE_AUTO_TYPE);
			}
			po.setCampaignID(campaign.getAutoID());
			po.setUpdatedTime(new Date());
			try {
				po.setNote(this.objectMapper.writer().writeValueAsString(campaignVo));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
				po.setNote("");
			}
			this.campaignLogRepository.save(po);
			log.debug("sync campaign CampaignLog: {}", po);
		}

		if (StringUtils.isNotBlank(dto.getTag()) && StringUtils.isNotBlank(dto.getTagType())) {
			campaign.setTagMessage(dto.getTag());
			campaign.setTagTypeName(dto.getTagType());
			Calendar cal = Calendar.getInstance();
			if (cal.get(Calendar.HOUR_OF_DAY) >= 16
					|| Math.abs(DateUtil.compareBetweenDay(new Date(), campaign.getTagTime())) > 1) {
				campaign.setTagTime(new Date());
			}
			this.campaignRepository.save(campaign);
		}

		log.debug("finish updateCampaign: {} {}", campaignID, dto);
		dto.setCampaignID(campaign.getAutoID());
		return dto;
	}

	public void toPlatformDto(CampaignDto dto, PlatformVo vo) {
		vo.setMobileDiscount(dto.getPlatform().getMobileDiscount());
		vo.setOutsideDiscount(dto.getPlatform().getOutsideDiscount());
		vo.setNonsearchChannels(new PlatformVo.Channels());
		vo.setSearchChannels(new PlatformVo.Channels());
		vo.getSearchChannels().setNumber(dto.getPlatform().toSearchChannels());
		vo.getNonsearchChannels().setNumber(dto.getPlatform().toNonsearchChannels());
	}

	public void toAreaDto(List<Integer> dtoList, List<Integer> campaignList, CampaignVo vo) {
		List<Integer> addArea = new ArrayList<Integer>(dtoList);
		List<Integer> lessArea = new ArrayList<Integer>(campaignList);
		addArea.removeAll(campaignList);
		lessArea.removeAll(dtoList);
		vo.setAddArea(new CampaignVo.Area());
		vo.getAddArea().setNums(addArea);
		vo.setLessArea(new CampaignVo.Area());
		vo.getLessArea().setNums(lessArea);
	}

	// 查看某一个推广计划
	@ApiOperation(value = "查看推广计划")
	@RequestMapping(method = RequestMethod.GET, path = "/campaigns/{campaign_id}")
	@ResponseBody
	public CampaignDto findCampaign(@PathVariable("campaign_id") long campaignID) {
		Campaign campaign = this.campaignRepository.findOne(campaignID);
		CampaignDto dto = new CampaignDto();
		// TODO:养分数，autonum数，2017/09/08后的迭代将不需要。可移除
		List<Campaign> campaigns = this.campaignRepository.findByUserID(campaign.getUserID());
		/* 查看该计划有没有线养分宝贝 **/
		List<Adgroup> adgroups = this.adgroupRepository.findByCampaignID(campaignID);
		int focusNum = 0;
		if (adgroups != null && adgroups.size() > 0) {
			for (Adgroup adgroup : adgroups) {
				if (adgroup.getDriveType() == DriveType.mix) {
					dto.setMixNum(dto.getMixNum() + 1);
				}
				if (adgroup.getDriveType() == DriveType.focus) {
					focusNum = focusNum + 1;
				}
			}
		}

		for (Campaign cam : campaigns) {
			if (cam.getAutoType() != DriveType.manual) {
				dto.setAutoCampaignNum(dto.getAutoCampaignNum() + 1);
			}
		}
		dto.from(campaign);
		PlatformVo vo = platformService.unserialize(campaign.getPlatform());
		if (vo != null) {
			dto.getPlatform().fromSearch(vo);
			dto.getPlatform().fromNonSearch(vo);
			dto.getPlatform().setMobileDiscount(vo.getMobileDiscount());
			dto.getPlatform().setOutsideDiscount(vo.getOutsideDiscount());
		}

		// 判断该计划是否还可推广
		long adgroupNum = this.adgroupRepository.countByCampaignID(campaignID);
		int productNum = this.productRepository.countByUserID(campaign.getUserID());
		if (productNum >= 2000) {
			if (2000 - adgroupNum > 0) {
				dto.setPromotable(true);
			}
		} else {
			if (productNum - adgroupNum > 0) {
				dto.setPromotable(true);
			}
		}

		if (campaign.getBudget() <= 50) {
			if (focusNum > 0) {
				dto.setCanFocusNum(focusNum - 1);
			} else {
				dto.setCanFocusNum(1);
			}

		} else {
			if (focusNum > 0) {
				dto.setCanFocusNum(focusNum - (int) Math.floor((float) (campaign.getBudget() / 50)));
			} else {
				dto.setCanFocusNum((int) Math.floor((float) (campaign.getBudget() / 50)));
			}
		}

		log.debug("finish readCampaign: {}", dto);
		return dto;
	}

	@ApiOperation(value = "查看推广计划的操作记录")
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@RequestMapping(method = RequestMethod.GET, path = "/campaigns/{campaign_id}/actions")
	@ResponseBody
	public Page<LogDto<LogDto.LogNoteable>> findCampaignLog(@PathVariable("campaign_id") long campaignID,
			@RequestParam(name = "type", defaultValue = "campaign") String type,
			@RequestParam(name = "page_num", defaultValue = "0") int page,
			@RequestParam(name = "page_size", defaultValue = "50") int size) {
		PageRequest pr = new PageRequest(page, size);

		Page<LogDto<LogDto.LogNoteable>> dtos = null;
		Date today = DateUtils.truncate(new Date(), Calendar.DATE);
		SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");

		if ("campaign".equals(type)) {
			Page<CampaignLog> logs = this.campaignLogRepository
					.findByCampaignIDAndUpdatedTimeAfterOrderByUpdatedTimeDesc(campaignID,
							DateUtils.addDays(today, -14), pr);
			List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
			for (CampaignLog clog : logs) {
				LogDto dto = new LogDto<CampaignVo>();
				BeanUtils.copyProperties(clog, dto);
				dto.setAction(clog.getAction().toDisplay());
				dto.setUpdatedTime(sdf.format(clog.getUpdatedTime()));
				if (!(clog.getNote().equals(""))) {
					try {
						dto.setNote(this.objectMapper.readerFor(CampaignVo.class).readValue(clog.getNote()));
					} catch (IOException e) {
						log.error("IOException: {}", e);
					}
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, logs.getTotalElements());
		} else {
			Page<AdgroupLog> logs = this.adgroupLogRepository.findByCampaignIDAndUpdatedTimeAfterOrderByUpdatedTimeDesc(
					campaignID, DateUtils.addDays(today, -14), pr);
			List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
			for (AdgroupLog alog : logs) {
				LogDto dto = new LogDto<AdgroupVo>();
				BeanUtils.copyProperties(alog, dto);
				dto.setAction(alog.getAction().toDisplay());
				dto.setUpdatedTime(sdf.format(alog.getUpdatedTime()));
				if (!(alog.getNote().equals(""))) {
					try {
						dto.setNote(this.objectMapper.readerFor(AdgroupVo.class).readValue(alog.getNote()));
					} catch (IOException e) {
						log.error("IOException:{}", e);
					}
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, logs.getTotalElements());
		}

		return dtos;

	}

	// 趋势图
	@ApiOperation(value = "查看推广计划每天的效果数据趋势")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "pc, mobile, all", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/campaigns/{campaign_id}/reports/trend", method = RequestMethod.GET)
	public @ResponseBody List<EffectMetricDto> reportsTrend(@PathVariable("campaign_id") Long campaignId,
			@RequestParam(required = false, defaultValue = "0") int days, @RequestParam(required = false) String device,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("reportsTrend RequestParam campaignId:{} days:{} device:{} startDate:{} endDate:{}", campaignId, days,
				device, startDate, endDate);
		RptKeywordParam param = RptKeywordParam.init();
		param.setUserId(campaignRepository.findOne(campaignId).getUserID());
		param.setCampaignId(campaignId);
		if (device != null) {
			param.setupDevice(device);
		}
		if (days > 0) {
			param.setupDays(days);
		}
		if (startDate != null) {
			param.setupDate(startDate, endDate);
		}

		List<RptKeyword> rpts = rptKeywordService.getReportsTrendByDate(param);
		List<EffectMetricDto> dtos = new ArrayList<EffectMetricDto>();
		if (rpts != null) {
			for (RptKeyword rpt : rpts) {
				EffectMetricDto dto = new EffectMetricDto();
				dto.filterNull(rpt);
				dto.from(rpt);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	// 指标摘要
	@ApiOperation(value = "查看推广计划效果数据摘要")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "pc, mobile, all", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/campaigns/{campaign_id}/summaries/metric", method = RequestMethod.GET)
	public @ResponseBody EffectMetricDto summariesMetric(@PathVariable("campaign_id") long campaignId,
			@RequestParam(required = false, defaultValue = "0") int days, @RequestParam(required = false) String device,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("summariesMetric RequestParam campaignId:{} days:{} device:{} startDate:{} endDate:{}", campaignId,
				days, device, startDate, endDate);
		RptKeywordParam param = RptKeywordParam.init();
		param.setUserId(campaignRepository.findOne(campaignId).getUserID());
		param.setCampaignId(campaignId);
		if (device != null) {
			param.setupDevice(device);
		}
		if (days > 0) {
			param.setupDays(days);
		}
		if (startDate != null) {
			param.setupDate(startDate, endDate);
		}
		RptKeyword rpt = rptKeywordService.getCampaignSummariesMetric(param);
		EffectMetricDto dto = new EffectMetricDto();
		if (rpt != null) {
			dto.filterNull(rpt);
			dto.from(rpt);
		}
		return dto;
	}

	// 推广组数据
	@ApiOperation(value = "查看推广计划下所有推广组的效果数据摘要")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "pc, mobile, all", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/campaigns/{campaign_id}/reports/adgroupStates", method = RequestMethod.GET)
	public @ResponseBody List<EffectMetricDto> adgroupStates(@PathVariable("campaign_id") Long campaignId,
			@RequestParam(required = false, defaultValue = "0") int days, @RequestParam(required = false) String device,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("adgroupStates RequestParam campaignId:{} days:{} device:{} startDate:{} endDate:{}", campaignId, days,
				device, startDate, endDate);
		RptKeywordParam param = RptKeywordParam.init();
		param.setUserId(campaignRepository.findOne(campaignId).getUserID());
		param.setCampaignId(campaignId);
		if (device != null) {
			param.setupDevice(device);
		}
		if (days > 0) {
			param.setupDays(days);
		}
		if (startDate != null) {
			param.setupDate(startDate, endDate);
		}

		List<RptKeyword> rpts = rptKeywordService.getReportsTrend(param);
		List<EffectMetricDto> dtos = new ArrayList<EffectMetricDto>();
		if (rpts != null) {
			for (RptKeyword rpt : rpts) {
				EffectMetricDto dto = new EffectMetricDto();
				dto.filterNull(rpt);
				dto.from(rpt);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@Data
	@EqualsAndHashCode(callSuper = true)
	@JsonInclude(Include.NON_NULL)
	public static class CampaignDto extends BaseDTO {
		private boolean success;

		@JsonProperty("campaign_id")
		private long campaignID;

		@JsonProperty("user_id")
		private long userID;

		private int budget;

		private String title;
		@JsonProperty("auto_type")
		private DriveType autoType;

		private Area area;

		private OnlineStatus onlineStatus;

		@JsonProperty("schedule_object")
		private ScheduleObject scheduleObject;

		private String schedule;

		private String platfromTemp;

		private ConvertPlatformVo platform;

		private ConvertPlatformVo convertPlatformVo; // 平台操作记录的转化
		@JsonProperty("auto_campaign_num")
		private int autoCampaignNum;

		@JsonProperty("can_focus_num")
		private int canFocusNum;
		@JsonProperty("mix_num")
		private int mixNum;
		@JsonProperty("campaign_limit")
		private int campaignLimit;

		@JsonProperty("effect_data")
		private EffectMetricDto effect;
		@JsonProperty("is_promotable")
		private boolean promotable;

		@JsonProperty("tag")
		private String tag;
		@JsonProperty("tag_type")
		private String tagType;

		private SimbaProxyBaseDto.Error error;

		@Override
		public void form(SimbaProxyBaseDto.Error error) {
			super.form(error);
		}

		public void from(Campaign campaign) {
			if (campaign.getArea().isAsAll() == true) {
				Integer[] arr = new Integer[] { 1, 39, 255, 279, 368, 417, 508, 19, 125, 333, 393, 461, 52, 351, 357,
						406, 471, 68, 92, 120, 145, 184, 212, 109, 438, 463, 488, 532, 165, 234, 294, 574, 576, 577,
						599 };
				campaign.getArea().setNums(Arrays.asList(arr));
				campaign.getArea().setAsAll(false);
			}
			BeanUtils.copyProperties(campaign, this);
			if (campaign.getTagTime() != null) {
				if (DateUtil.compareBetweenDay(
						DateUtil.parseDate2date(DateFormatUtils.format(new Date(), "yyyy-MM-dd")),
						campaign.getTagTime()) == 1) {
					this.setTag(campaign.getTagMessage());
					this.setTagType(campaign.getTagTypeName());
				}
			}
			this.setCampaignID(campaign.getAutoID());
			this.setAutoType(campaign.getAutoType());
			this.setPlatform(new ConvertPlatformVo());
			if ("all".equals(campaign.getSchedule())) {
				this.setSchedule(WHOLE_DAY);
			}
			this.setScheduleObject(CampaignUtils.toScheduleObject(this.getSchedule()));
		}
	}

	@ApiOperation(value = "查看推广计划的关键词")
	@RequestMapping(method = RequestMethod.GET, path = "/campaigns/{campaign_id}/keywords")
	@ResponseBody
	public ListResponse<Keyword> findKeywords(@PathVariable("campaign_id") long campaignID,
			@RequestParam(name = "filters", defaultValue = "max_price") List<String> filters,
			@RequestParam(name = "max_price", required = false, defaultValue = "0") int maxPrice) {

		List<Adgroup> adgroups = this.adgroupRepository.findByCampaignID(campaignID);

		ListResponse<Keyword> dto = new ListResponse<Keyword>();
		dto.setDatas(new ArrayList<Keyword>());
		int adgroupCount = 0;
		for (Adgroup adgroup : adgroups) {
			if (adgroup.getLimit() > 0) {
				adgroupCount++;
			}
		}
		dto.setTemp(dto.getDatas().size()); // 统计的是关键词要修改的总数
		dto.setTotal(adgroupCount);
		dto.setStatus(true);

		return dto;
	}

	@ApiOperation(value = "查看推广计划的报表数据")
	@RequestMapping(method = RequestMethod.GET, path = "/campaigns/{campaign_id}/rptCampaign")
	@ResponseBody
	public RptCampaign findRptCampaign(@PathVariable("campaign_id") long campaignID,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate,
			@RequestParam(name = "days", required = false, defaultValue = "0") int days) {

		RptKeywordExample example = new RptKeywordExample();
		RptKeywordExample.Criteria criteria = example.createCriteria();
		criteria.andCampaignIdEqualTo(campaignID);
		if (startDate != null && !startDate.equals("") && endDate != null && !endDate.equals("")) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			try {
				criteria.andDateBetween(sdf.parse(startDate), sdf.parse(endDate));
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				log.error("RptCampaign paramToExample date parse:{}", e.getMessage());
			}
		}
		if (days > 0) {
			Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
			criteria.andDateBetween(DateUtils.addDays(yesterday, 1 - days), yesterday);
		}
		RptCampaign rptCampaign = this.rptCampaignService.selectByCampaignIdAndDate(example);

		return rptCampaign;
	}

	@ApiOperation(value = "批量获取推广计划")
	@RequestMapping(method = RequestMethod.GET, path = "/users/{user_id}/campaigns")
	@ResponseBody
	public List<CampaignDto> query(@PathVariable("user_id") final long userID,
			@RequestParam(name = "campaign_id", required = false, defaultValue = "0") final long campaignID,
			@RequestParam(name = "need_rpt", required = false, defaultValue = "false") boolean needRpt,
			@RequestParam(name = "start", required = false) String start,
			@RequestParam(name = "end", required = false) String end) {
		List<Campaign> pos = this.campaignRepository.findAll(new Specification<Campaign>() {
			@Override
			public Predicate toPredicate(Root<Campaign> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate p = cb.equal(root.get("userID"), userID);
				if (campaignID > 0) {
					p = cb.and(p, cb.equal(root.get("autoID"), campaignID));
				}
				return p;
			}
		});
		List<CampaignDto> dtos = new ArrayList<CampaignDto>();
		Map<Long, CampaignDto> dtoMap = new HashMap<Long, CampaignDto>();
		if (pos != null && pos.size() > 0) {
			for (Campaign po : pos) {
				CampaignDto dto = new CampaignDto();
				dto.from(po);
				PlatformVo vo = platformService.unserialize(po.getPlatform());
				if (vo != null) {
					dto.getPlatform().fromSearch(vo);
					dto.getPlatform().fromNonSearch(vo);
					dto.getPlatform().setMobileDiscount(vo.getMobileDiscount());
					dto.getPlatform().setOutsideDiscount(vo.getOutsideDiscount());
				}
				dtoMap.put(po.getAutoID(), dto);
				dtos.add(dto);
			}
		}

		if (needRpt) {
			if (pos != null && pos.size() > 0) {
				for (Campaign po : pos) {
					CampaignDto dto = dtoMap.get(po.getAutoID());
					if (dto != null) {
						// TODO:需优化
						dto.setEffect(this.summariesMetric(po.getAutoID(), 0, null, start, end));
					}

				}
			}
		}

		return dtos;
	}

	@ApiOperation(value = "获取有效代理用户的所有计划id")
	@RequestMapping(method = RequestMethod.GET, path = "/campaigns/@ids")
	@ResponseBody
	public List<Long> findCampaignIDs() {
		List<User> pos = this.userRepository.findAll(new Specification<User>() {
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate p = cb.equal(root.get("userType"), 2);
				return p;
			}
		});
		List<Long> userIDs = new ArrayList<Long>();
		if (pos == null || pos.size() == 0) {
			return userIDs;
		}
		for (User po : pos) {
			if (userIDs.indexOf(po.getUserID()) == -1) {
				userIDs.add(po.getUserID());
			}
		}
		List<Long> campaignIDs = new ArrayList<Long>();

		List<Long> IDs = this.campaignRepository.findCampaignIDsByUserIDs(userIDs);
		if (IDs == null || IDs.size() == 0) {
			return campaignIDs;
		}
		campaignIDs.addAll(IDs);

		return campaignIDs;
	}
}
